/**
 * @brief 计时器模块
 * @author 宋炜
 * @date 2024-04-07
 * @version 1.0
 */
const { OrderedMap } = require( 'js-sdsl' )

class timer
{
    constructor( id , tick , oneshot )
    {
        this.m_id__ = id;
        this.m_tick__ = tick;              // 需要及时的数量
        this.m_abs_tick__ = 0;             // 相对于管理器的tick
        this.m_is_oneshot__ = oneshot;
        
        this.m_func__ = null;

        this.m_mgr__ = null;
    }

    ID()
    {
        return this.m_id__;
    }
    /**
     * 指定或者配置绝对时间
     * @param {*} tick 
     */
    setAbsTick( tick )
    {
        this.m_abs_tick__ = tick;
    }

    getAbsTick()
    {
        return this.m_abs_tick__;
    }
    /**
     * 通知函数
     * @param {*} func 
     */
    on( func )
    {
        if( typeof( func ) != 'function' ){
            throw '参数必须是一个函数对象';
        }

        this.m_func__ = func;
    }

    setManager( mgr )
    {
        this.m_mgr__ = mgr;
    }

    start()
    {
        this.m_mgr__.add__( this );
    }

    stop()
    {
        this.m_mgr__.remove__( this );
    }

    emitEvent()
    {
        let this_ = this;
        
        this_.m_func__();
    }

    get_tick__(){ return this.m_tick__; }
};
/**
 * @brief 计时器管理模块
 */
class timerEgnx {
    __m_timer_id_seed = 0;          // 定时器计数
    __m_granularity = 10;           // 计时器粒度
    __m_timer_tick = 0;
    __m_timer_id = null;            // 定时器id

    __m_topk = new OrderedMap();
    /**
     * 
     * @param {*} granularity 计时粒度
     */
    constructor(granularity) 
    {
        this.__m_granularity = granularity;
    }

    granularity()
    {
        return this.__m_granularity;
    }
    /**
     * 获取当前计时的绝对计数
     * @returns 
     */
    get_tick__()
    {
        return this.__m_timer_tick;
    }
    /**
     * 启动计时器
     * @returns 
     */
    start() {
        if (this.__m_timer_id != null) {
            global.gLOGGER.error(`[timer] [start] 定时器正在运行, 不能重复启动`);
            return;
        }

        this.__m_timer_id = setInterval(()=>{
            this.on_timer__();
            //global.gLOGGER.info( `计时器触发, 计时次数：${this.__m_timer_tick}` );
            this.__m_timer_tick ++;
        } , this.__m_granularity );
    }
    /**
     * 停止计时器
     */
    stop() {
        if (this.__m_timer_id != null) {
            clearInterval(this.__m_timer_id);
            global.logger.log(`[Timer] [stop] [${this.__m_granularity}]计时器已停止`);
        }
    }
    /**
     * 向堆中添加节点
     * @param {number} time
     * @param {object} obj 
     */
    createTimer( tick , oneshot )
    {
        let ret = new timer( this.__m_timer_id_seed ++ ,  tick , oneshot );
        ret.setManager( this );
        return ret;
    }
// private:
    /**
     * 向计时表中添加数据
     * @param {*} t 
     */
    add__( t )
    {
        let tick = t.get_tick__() + this.__m_timer_tick  ;
        t.setAbsTick( tick );

        let obj = this.__m_topk.getElementByKey( tick );
        if( obj ){
            obj.push( t );
            this.__m_topk.setElement( tick , obj );
        }else{
            let ary = new Array();
            ary.push( t );
            this.__m_topk.setElement( tick, ary );
        }
    }

    remove__( t )
    {
        let tick = t.getAbsTick();
        let obj = this.__m_topk.getElementByKey( tick );

        if( this.__m_topk.find( tick ) !=  this.__m_topk.end() ){
            for( let idx in obj ){
                if( obj[ idx ].m_id__ == t.m_id__ ){
                    obj.splice( idx , 1 );
                    break;
                }
            }

            if( obj.length == 0 ){
                this.__m_topk.eraseElementByKey( tick );
            }
        }
    }
    /**
     * 监测是否需要触发任务
     */
    on_timer__() {
        try {
            // 找出已经到期的计时器，发出通知
            if( this.__m_topk.size() == 0 ) return;
            // 不存在软件计时器
            let key = this.__m_topk.getElementByPos( 0 );
            
            // 目标时间还没有到，继续计数
            if( key[ 0 ] > this.__m_timer_tick ){ return; }
            // 事件已经到了，触发通知
            const arr = key[ 1 ];
            for (let i = arr.length - 1; i >= 0; i--) {
                const dd = arr[i];
                this.remove__( dd );
                if (dd.m_is_oneshot__ == false ) {
                    this.add__( dd );
                }
                // 触发计时器通知
                dd.emitEvent();
            }

            if (arr.length == 0) {
                this.__m_topk.eraseElementByKey( key[ 0 ] );
            }
        } catch (e) {
            global.gLOGGER.error(`[Timer] [on_timer__] 触发任务失败: ${e.toString()}`);
        }

        this.__m_timer_tick ++;
    }
}


module.exports = timerEgnx;